# coding:utf-8
import json
import os
import random
import traceback
from datetime import datetime
from time import time, sleep
import jieba
import requests
from flask import jsonify, request, current_app, g
from sqlalchemy import or_

from app.libs.ParseArticles import ParseArticle
from app.libs.aigc_tools import PasreArticle
from app.libs.poster import PosterGenerator
from app.libs.token_auth import auth
from app import redisclient, redisclientRemote
from app.api.v1.article import insertSelfDababase
from app.libs.ParseDocument import ParseDocument
from app.libs.ParseDocumentHtml import ParseDocumentHtml
from app.libs.createLocalIndex import CreatLocalIndex, CreatLocalIndexRemote
from app.libs.error_code import Success
from app.libs.redprint import Redprint
from app.models.AmountLog import AmountLog
from app.models.ai_sentence import AISentence
from app.models.aigc_content import aigc_content
from app.models.aigc_order_info import aigc_order_info
from app.models.aigc_paragraphs import AigcParagraphs
from app.models.aigc_report_info import aigc_report_info
from app.models.captcha import captcha
from app.models.document_dom import DocumentDom
from app.models.report_info import report_info
from app.models.sentences_word import SentenceWord
from app.models.share_log import ShareLog
from app.models.taobao_orders import taobao_orders
from app.models.base import db
from app.models.order_info import order_info
from app.models.orders import orders
from app.models.paragraphs import Paragraphs
from app.models.sentence import sentence
from app.models.user import User
from app.models.writer_orders import writer_orders
from app.taobao_api.get_order_status import Order_Status
from app.validators.article import ArticleSubmitForm, ReportSearchForm, ShopForm, DocUploadForm, DeleteReportForm, \
    WriterOrderNumber, WriterArticleSubmitForm, WriterReportSearchForm, ReArticleSubmitForm, ArticleBatchSubmitForm, \
    MutilDocUploadForm, AIRewriteForm, UnitForm, ArticleSubmitByUploadForm, ArticleSubmitByPasteForm
from app.validators.wx_article import UnlockAigcByWxPay, UnlockAigcNeedShareCountForm, WxSearchReport, WxVerifyOrderNumberForm
from app.view_models.OrderInfo import OrderInfolistView
from app.libs.tools import cut_sentences, get_key_words, parseDocument, check_paragrpah, \
    float2decimal
from app.config.setting import *
from app import executor
from app.view_models.WxReportInfo import WxReportInfoListView

api = Redprint('wx_article')


@api.route("/submit_by_upload", methods=['POST'])
@auth.login_required
def submit_by_upload():
    form = ArticleSubmitByUploadForm(g).validate_for_api()
    current_time = str(round(time() * 1000))
    order_number = f'88{current_time}'
    with db.auto_commit():
        order = orders()
        order.order_number = order_number
        order.content = form.content.data
        order.author = form.author.data
        order.char_sum = form.chars_sum.data
        order.title = form.title.data
        db.session.add(order)
        report_info_model = report_info()
        report_info_model.order_number = order_number
        report_info_model.title = form.title.data
        report_info_model.author = form.author.data
        report_info_model.chars_sum = form.chars_sum.data
        report_info_model.user = g.user.uid
        report_info_model.pay_type = form.paytype.data
        report_info_model.out_trade_no = form.out_trade_no.data
        db.session.add(report_info_model)
        if form.taobao_orders != []:
            for taobao_order in form.taobao_orders:
                info = order_info()
                info.taobao_orders = taobao_order
                info.order_number = order_number
                info.title = form.title.data
                info.chars_sum = form.chars_sum.data
                info.author = form.author.data
                info.file_path = form.file_path.data
                info.user = g.user.uid
                info.pay_type = form.paytype.data
                info.out_trade_no = form.out_trade_no.data
                db.session.add(info)
        else:
            info = order_info()
            info.taobao_orders = ''
            info.order_number = order_number
            info.title = form.title.data
            info.chars_sum = form.chars_sum.data
            info.author = form.author.data
            info.file_path = form.file_path.data
            info.user = g.user.uid
            info.pay_type = form.paytype.data
            info.out_trade_no = form.out_trade_no.data
            db.session.add(info)
        if form.paytype.data != 'taobao':
            amount_log = AmountLog()
            amount_log.amount = form.amount.data
            amount_log.modify_log = f'查重消费{form.amount.data}'
            amount_log.transaction_id = ''
            amount_log.type = 'out'
            amount_log.user_id = g.user.uid
            db.session.add(amount_log)
            User.query.filter_by(id=g.user.uid).update({
                'amount': User.amount - form.amount.data
            })
        user_info = User.query.filter_by(id=g.user.uid).first()
        if user_info.gzh_open_id == '':
            gzh_open_id = User.getGzhOpenId(user_info.union_id)
            User.query.filter_by(id=g.user.uid).update({
                'gzh_open_id': gzh_open_id
            })
        if user_info.free_chars > 0:
            remain_free_chars = user_info.free_chars - form.chars_sum.data if user_info.free_chars >= form.chars_sum.data else 0
            User.query.filter_by(id=g.user.uid).update({
                'free_chars': remain_free_chars
            })
    # # db_document_operation(form.file_path.data, order_number)
    executor.submit(__db_document_operation, form.file_path.data, order_number,
                    current_app._get_current_object())
    executor.submit(__db_submit_aigc_check, form.title.data, form.author.data, form.chars_sum.data, form.content.data,
                    g.user.uid, order_number, current_app._get_current_object())
    return Success()


@api.route("/submit_by_paste", methods=['POST'])
@auth.login_required
def submit_by_paste():
    form = ArticleSubmitByPasteForm(g).validate_for_api()
    current_time = str(round(time() * 1000))
    order_number = f'99{current_time}'
    with db.auto_commit():
        order = orders()
        order.order_number = order_number
        order.content = form.content.data
        order.author = form.author.data
        order.char_sum = form.chars_sum.data
        order.title = form.title.data
        db.session.add(order)
        report_info_model = report_info()
        report_info_model.order_number = order_number
        report_info_model.title = form.title.data
        report_info_model.author = form.author.data
        report_info_model.chars_sum = form.chars_sum.data
        report_info_model.user = g.user.uid
        report_info_model.pay_type = form.paytype.data
        report_info_model.out_trade_no = form.out_trade_no.data
        db.session.add(report_info_model)

        if form.taobao_orders != []:
            for taobao_order in form.taobao_orders:
                info = order_info()
                info.taobao_orders = taobao_order
                info.order_number = order_number
                info.title = form.title.data
                info.chars_sum = form.chars_sum.data
                info.author = form.author.data
                info.user = g.user.uid
                info.pay_type = form.paytype.data
                info.out_trade_no = form.out_trade_no.data
                db.session.add(info)
        else:
            info = order_info()
            info.taobao_orders = ''
            info.order_number = order_number
            info.title = form.title.data
            info.chars_sum = form.chars_sum.data
            info.author = form.author.data
            info.user = g.user.uid
            info.pay_type = form.paytype.data
            info.out_trade_no = form.out_trade_no.data
            db.session.add(info)
        if form.paytype.data != 'taobao':
            amount_log = AmountLog()
            amount_log.amount = form.amount.data
            amount_log.modify_log = f'查重消费{form.amount.data}'
            amount_log.transaction_id = ''
            amount_log.type = 'out'
            amount_log.user_id = g.user.uid
            db.session.add(amount_log)
            User.query.filter_by(id=g.user.uid).update({
                'amount': User.amount - form.amount.data
            })

        user_info = User.query.filter_by(id=g.user.uid).first()
        if user_info.gzh_open_id == '':
            gzh_open_id = User.getGzhOpenId(user_info.union_id)
            User.query.filter_by(id=g.user.uid).update({
                'gzh_open_id': gzh_open_id
            })
        if user_info.free_chars > 0:
            remain_free_chars = user_info.free_chars - form.chars_sum.data if user_info.free_chars >= form.chars_sum.data else 0
            User.query.filter_by(id=g.user.uid).update({
                'free_chars': remain_free_chars
            })

    # content, paragraph_content = cut_sentences(form.content.data)
    executor.submit(__db_operation, order_number, form.content.data,
                    current_app._get_current_object())
    executor.submit(__db_submit_aigc_check, form.title.data, form.author.data, form.chars_sum.data, form.content.data,
                    g.user.uid, order_number, current_app._get_current_object())
    return Success()


@api.route('/search', methods=['POST'])
@auth.login_required
def search():
    form = WxSearchReport(g).validate_for_api()
    view = WxReportInfoListView()
    now = int(time())
    reports = report_info.query.filter_by(user=g.user.uid).filter(now - report_info.create_time<86400 * 7).order_by(report_info.create_time.desc()).paginate(
        form.page.data,
        form.limit.data,
        error_out=False)

    view.fill(reports)
    return jsonify(view)


@api.route('/unlock_aigc_need_share_count',methods=['POST'])
@auth.login_required
def unlock_aigc_need_share_count():
    form = UnlockAigcNeedShareCountForm().validate_for_api()
    shares = ShareLog.query.filter_by(order_number=form.order_number.data).filter_by(report_type=form.report_type.data).all()
    count = len(shares)
    return jsonify({
        'unlock_aigc_need_share_count' : 3-count
    })
    
@api.route('/unlock_by_wxpay', methods=['POST'])
@auth.login_required
def unlock_by_wxpay():
    form = UnlockAigcByWxPay().validate_for_api()
    with db.auto_commit():
        aigc_order_info.query.filter_by(order_number=form.order_number.data).update({
            'lock': 0,
            'pay_type': 'wxpay',
            'out_trade_no': form.out_trade_no.data
        })
        amount_log = AmountLog()
        amount_log.amount = form.amount.data
        amount_log.modify_log = f'解锁aigc报告消费{form.amount.data}'
        amount_log.transaction_id = ''
        amount_log.type = 'out'
        amount_log.user_id = g.user.uid
        db.session.add(amount_log)
        User.query.filter_by(id=g.user.uid).update({
            'amount': User.amount - form.amount.data
        })
    return Success()
    


@api.route('/taobao_order_info', methods=['POST'])
@auth.login_required
def taobao_order_info():
    form = WxVerifyOrderNumberForm().validate_for_api()
    info = taobao_orders.query.filter_by(order_number=form.order_number.data).first()
    if info:
        return jsonify(info)
    else:
        order_status = Order_Status(form.order_number.data, 0, 'TbAldszyw2zfa35ttemzxhbh2zkx27x6mabxssreswt2vkxgxt')
        info = order_status.tidInfo(form.order_number.data)
        return jsonify(info)


@api.route('/upload', methods=['POST'])
@auth.login_required
def upload():
    form = DocUploadForm(g).validate_for_api()
    res = {
        'content': form.content.data,
        'file_path': form.filePath.data,
        'char_sum': form.char_sum.data,
        'filename': form.showfilename.data,
        'error_code': 0
    }
    return jsonify(res)


@api.route('/unit_price', methods=['POST'])
@auth.login_required
def unit_price():
    unit_price = redisclient.getRepetitionPrice()
    return jsonify({'unit_price': unit_price})

@api.route(rule='/unlock_poster', methods=['POST'])
@auth.login_required
def unlock_poster():
    bot = PosterGenerator()
    bot.unlockAIGCPoster()
    return jsonify({'unit_price': 1.5})




def __db_operation(order_number,content, app):
    try:
        with app.app_context():
            with db.auto_commit():
                parseModel = ParseArticle(content)
                parseModel.cut()
                paragraph_model = Paragraphs()
                sentence_model = sentence()
                target_redisclient = redisclientRemote
                paragraph_model.insert_paragrahs(parseModel.paragraph_content, order_number)
                sentence_model.insert_sentences(parseModel.contents, order_number)
                es_model = CreatLocalIndex()
                check_sentences = sentence.query.filter_by(order_number=order_number).filter_by(check=1).order_by(
                sentence.check_id).all()
                target_redisclient.setCheckData(check_sentences, 2, [])
                es_model.createLocalIndex(order_number)
                target_redisclient.hset_task(order_number)
                target_redisclient.push_task(LOCAL_TASK, order_number)
                check_part = ''
                for item in check_sentences:
                    if item['check'] == 1:
                        check_part += item['content']
                        if len(check_part) > 1000:
                            try:
                                keywords = get_key_words(check_part)
                                target_redisclient.client.rpush(f'{KEYWORDS_INTERNET}{order_number}', keywords)
                            except Exception as e:
                                print(order_number, str(e))
                            check_part = ''
                try:
                    keywords = get_key_words(check_part)
                    target_redisclient.client.rpush(f'{KEYWORDS_INTERNET}{order_number}', keywords)
                except Exception as e:
                    print(order_number, str(e))
                target_redisclient.push_task(PRE_INTERNET_TASK, order_number)
        print('save data complete!')
    except Exception as e:
        print(e)


def __db_document_operation(file_path, order_number, app):
    with app.app_context():
        try:
            with db.auto_commit():
                parseDocument(file_path, order_number)

                Document = ParseDocumentHtml(order_number)
                Document.parseDom()
                documentDoms = DocumentDom()
                documentDoms.insert_doms(Document.domModel)

                paragraphs = DocumentDom.query.filter_by(order_number=order_number).filter_by(paragraph=1).all()

                parseModel = ParseDocument(paragraphs)
                parseModel.cut()
                sentenceWordModel = SentenceWord()
                sentenceWordModel.insert_sentences(parseModel.contents, order_number)
                target_redisclient = redisclientRemote
                es_model = CreatLocalIndex()
                check_sentences = SentenceWord.query.filter_by(order_number=order_number).filter_by(check=1).order_by(
                    SentenceWord.check_id).all()
                target_redisclient.setCheckData(check_sentences, checkmodel=2, selffileList=[])
                es_model.createLocalIndex(order_number)
                target_redisclient.hset_task(order_number)
                target_redisclient.hset_task(order_number)
                target_redisclient.push_task(LOCAL_TASK, order_number)
                check_part = ''
                for item in check_sentences:
                    if item['check'] == 1:
                        check_part += item['content']
                        if len(check_part) > 1000:
                            try:
                                keywords = get_key_words(check_part)
                                target_redisclient.client.rpush(f'{KEYWORDS_INTERNET}{order_number}', keywords)
                            except Exception as e:
                                print(order_number, str(e))
                            check_part = ''
                target_redisclient.push_task(PRE_INTERNET_TASK, order_number)
        except Exception as e:
            traceback.print_exc()


def __db_submit_aigc_check(title, author, chars_sum, content, uid, order_number, app):
    try:
        with app.app_context():
            with db.auto_commit():
                aigc_content_model = aigc_content()
                aigc_content_model.order_number = order_number
                aigc_content_model.content = content
                aigc_content_model.author = author
                aigc_content_model.char_sum = chars_sum
                aigc_content_model.title = title
                db.session.add(aigc_content_model)

                info = aigc_order_info()
                info.taobao_orders = ''
                info.order_number = order_number
                info.title = title
                info.chars_sum = chars_sum
                info.author = author
                info.file_path = ''
                info.user = uid
                info.lock = 1
            
                db.session.add(info)

            parseModel = PasreArticle(content)
            parseModel.run()
            with db.auto_commit():
                for fragment in parseModel.ArticleStruct:
                    if fragment['content'].strip() != '':
                        paragraphModel = AigcParagraphs()
                        paragraphModel.order_number = order_number
                        paragraphModel.paragraph_index = fragment['paragraph_index']
                        paragraphModel.content = fragment['content'].strip()
                        paragraphModel.type = fragment['type']
                        db.session.add(paragraphModel)
            target_redisclient = redisclientRemote
            target_redisclient.push_task(AIGC_TASK, order_number)
    except Exception as e:
        print(e)
